#ifdef USE_OPENCV
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#endif  // USE_OPENCV

#ifndef CAFFE_UTIL_BBOX_UTIL_H_
#define CAFFE_UTIL_BBOX_UTIL_H_

#include <stdint.h>
#include <cmath>  // for std::fabs and std::signbit
#include <map>
#include <string>
#include <utility>
#include <vector>

#include "blob.hpp"

namespace ts {

namespace caffe {

#define _CONCAT_NAME_CORE(x,y) (x##y)
#define _CONCAT_NAME(x, y) _CONCAT_NAME_CORE(x,y)
#define _MESSAGE_ATTR(type, name, value) \
    private: type _CONCAT_NAME(m_, name) = value;    \
    public: const type &name() const { return _CONCAT_NAME(m_, name); }  \
            void _CONCAT_NAME(set_, name)(const type &val) { _CONCAT_NAME(m_, name) = val; } \
            bool _CONCAT_NAME(has_, name)() const { return _CONCAT_NAME(m_, name) != value; } \
            void _CONCAT_NAME(clear_, name)() { _CONCAT_NAME(m_, name) = value; }

    class NormalizedBBox {
        _MESSAGE_ATTR(float, xmin, 0)
        _MESSAGE_ATTR(float, ymin, 0)
        _MESSAGE_ATTR(float, xmax, 0)
        _MESSAGE_ATTR(float, ymax, 0)
        _MESSAGE_ATTR(int32_t, label, 0)
        _MESSAGE_ATTR(bool, difficult, false)
        _MESSAGE_ATTR(float, score, 0)
        _MESSAGE_ATTR(float, size, 0)
    };

    class EmitConstraint {
    public:
        enum EmitType {
            CENTER = 0,
            MIN_OVERLAP = 1,
        };
        _MESSAGE_ATTR(EmitType, emit_type, CENTER)
        _MESSAGE_ATTR(float, emit_overlap, 0)
    };

    class ResizeParameter {
    public:
        enum Resize_mode {
            NOT_SET = 0,
            WARP = 1,
            FIT_SMALL_SIZE = 2,
            FIT_LARGE_SIZE_AND_PAD = 3,
        };
        _MESSAGE_ATTR(Resize_mode, resize_mode, WARP)
        _MESSAGE_ATTR(int32_t, height, 0)
        _MESSAGE_ATTR(int32_t, width, 0)
        _MESSAGE_ATTR(int32_t, height_scale, 0)
        _MESSAGE_ATTR(int32_t, width_scale, 0)
    };

    class PriorBoxParameter {
    public:
        enum CodeType {
            CORNER = 1,
            CENTER_SIZE = 2,
            CORNER_SIZE = 3,
        };
    };

    class NonMaximumSuppressionParameter {
    public:
        using self = NonMaximumSuppressionParameter;

        _MESSAGE_ATTR(float, nms_threshold, 0.3)
        _MESSAGE_ATTR(int32_t, top_k, 0)
        _MESSAGE_ATTR(float, eta, 1.0)

        bool operator==(const self &other) const {
            return this->m_nms_threshold == other.m_nms_threshold
                   && this->m_top_k == other.m_top_k
                   && this->m_eta == other.m_eta;
        }

        bool operator!=(const self &other) const {
            return !this->operator==(other);
        }
    };

    class MultiBoxLossParameter {
    public:
        enum LocLossType {
            L2 = 0,
            SMOOTH_L1 = 1,
        };
        enum ConfLossType {
            SOFTMAX = 0,
            LOGISTIC = 1,
        };
        enum MatchType {
            BIPARTITE = 0,
            PER_PREDICTION = 1,
        };
        enum MiningType {
            NONE = 0,
            MAX_NEGATIVE = 1,
            HARD_EXAMPLE = 2,
        };
        _MESSAGE_ATTR(LocLossType, loc_loss_type, SMOOTH_L1)
        _MESSAGE_ATTR(ConfLossType, conf_loss_type, SOFTMAX)
        _MESSAGE_ATTR(MatchType, match_type, PER_PREDICTION)
        _MESSAGE_ATTR(MiningType, mining_type, MAX_NEGATIVE)
        _MESSAGE_ATTR(int32_t, num_classes, 0)
        _MESSAGE_ATTR(bool, share_location, false)
        _MESSAGE_ATTR(float, overlap_threshold, 0)
        _MESSAGE_ATTR(bool, use_prior_for_matching, true)
        _MESSAGE_ATTR(int32_t, background_label_id, 0)
        _MESSAGE_ATTR(PriorBoxParameter::CodeType , code_type, PriorBoxParameter::CORNER)
        _MESSAGE_ATTR(bool, encode_variance_in_target, false)
        _MESSAGE_ATTR(bool, ignore_cross_boundary_bbox, false)
        _MESSAGE_ATTR(bool, bp_inside, false)
        _MESSAGE_ATTR(bool, map_object_to_agnostic, false)
        _MESSAGE_ATTR(bool, do_neg_mining, false)
        _MESSAGE_ATTR(bool, use_prior_for_nms, false)
        _MESSAGE_ATTR(float, neg_pos_ratio, 0)
        _MESSAGE_ATTR(float, neg_overlap, 0)
        _MESSAGE_ATTR(int32_t, sample_size, 64)
        _MESSAGE_ATTR(NonMaximumSuppressionParameter, nms_param, NonMaximumSuppressionParameter())
    };

#undef _MESSAGE_ATTR
#undef _CONCAT_NAME
#undef _CONCAT_NAME_CORE

    template <typename K, typename V>
    using map = std::map<K, V>;
    template <typename T>
    using vector = std::vector<T>;
    template <typename K, typename V>
    using pair = std::pair<K, V>;
    using string = std::string;
    template <typename T>
    using set = std::set<T>;


    typedef EmitConstraint::EmitType EmitType;
    typedef PriorBoxParameter::CodeType CodeType;
    typedef MultiBoxLossParameter::MatchType MatchType;
    typedef MultiBoxLossParameter::LocLossType LocLossType;
    typedef MultiBoxLossParameter::ConfLossType ConfLossType;
    typedef MultiBoxLossParameter::MiningType MiningType;

    typedef map<int, vector<NormalizedBBox> > LabelBBox;

// Function used to sort NormalizedBBox, stored in STL container (e.g. vector),
// in ascend order based on the score value.
    bool SortBBoxAscend(const NormalizedBBox& bbox1, const NormalizedBBox& bbox2);

// Function used to sort NormalizedBBox, stored in STL container (e.g. vector),
// in descend order based on the score value.
    bool SortBBoxDescend(const NormalizedBBox& bbox1, const NormalizedBBox& bbox2);

// Function sued to sort pair<float, T>, stored in STL container (e.g. vector)
// in descend order based on the score (first) value.
    template <typename T>
    bool SortScorePairAscend(const pair<float, T>& pair1,
                             const pair<float, T>& pair2);

// Function sued to sort pair<float, T>, stored in STL container (e.g. vector)
// in descend order based on the score (first) value.
    template <typename T>
    bool SortScorePairDescend(const pair<float, T>& pair1,
                              const pair<float, T>& pair2);

// Generate unit bbox [0, 0, 1, 1]
    NormalizedBBox UnitBBox();

// Check if a bbox is cross boundary or not.
    bool IsCrossBoundaryBBox(const NormalizedBBox& bbox);

// Compute the intersection between two bboxes.
    void IntersectBBox(const NormalizedBBox& bbox1, const NormalizedBBox& bbox2,
                       NormalizedBBox* intersect_bbox);

// Compute bbox size.
    float BBoxSize(const NormalizedBBox& bbox, const bool normalized = true);

    template <typename Dtype>
    Dtype BBoxSize(const Dtype* bbox, const bool normalized = true);

// Clip the NormalizedBBox such that the range for each corner is [0, 1].
    void ClipBBox(const NormalizedBBox& bbox, NormalizedBBox* clip_bbox);

// Clip the bbox such that the bbox is within [0, 0; width, height].
    void ClipBBox(const NormalizedBBox& bbox, const float height, const float width,
                  NormalizedBBox* clip_bbox);

// Scale the NormalizedBBox w.r.t. height and width.
    void ScaleBBox(const NormalizedBBox& bbox, const int height, const int width,
                   NormalizedBBox* scale_bbox);

// Output predicted bbox on the actual image.
    void OutputBBox(const NormalizedBBox& bbox, const pair<int, int>& img_size,
                    const bool has_resize, const ResizeParameter& resize_param,
                    NormalizedBBox* out_bbox);

// Locate bbox in the coordinate system that src_bbox sits.
    void LocateBBox(const NormalizedBBox& src_bbox, const NormalizedBBox& bbox,
                    NormalizedBBox* loc_bbox);

// Project bbox onto the coordinate system defined by src_bbox.
    bool ProjectBBox(const NormalizedBBox& src_bbox, const NormalizedBBox& bbox,
                     NormalizedBBox* proj_bbox);

// Extrapolate the transformed bbox if height_scale and width_scale is
// explicitly provided, and it is only effective for FIT_SMALL_SIZE case.
    void ExtrapolateBBox(const ResizeParameter& param, const int height,
                         const int width, const NormalizedBBox& crop_bbox, NormalizedBBox* bbox);

// Compute the jaccard (intersection over union IoU) overlap between two bboxes.
    float JaccardOverlap(const NormalizedBBox& bbox1, const NormalizedBBox& bbox2,
                         const bool normalized = true);

    template <typename Dtype>
    Dtype JaccardOverlap(const Dtype* bbox1, const Dtype* bbox2);

// Compute the coverage of bbox1 by bbox2.
    float BBoxCoverage(const NormalizedBBox& bbox1, const NormalizedBBox& bbox2);

// Encode a bbox according to a prior bbox.
    void EncodeBBox(const NormalizedBBox& prior_bbox,
                    const vector<float>& prior_variance, const CodeType code_type,
                    const bool encode_variance_in_target, const NormalizedBBox& bbox,
                    NormalizedBBox* encode_bbox);

// Check if a bbox meet emit constraint w.r.t. src_bbox.
    bool MeetEmitConstraint(const NormalizedBBox& src_bbox,
                            const NormalizedBBox& bbox, const EmitConstraint& emit_constraint);

// Decode a bbox according to a prior bbox.
    void DecodeBBox(const NormalizedBBox& prior_bbox,
                    const vector<float>& prior_variance, const CodeType code_type,
                    const bool variance_encoded_in_target, const bool clip_bbox,
                    const NormalizedBBox& bbox, NormalizedBBox* decode_bbox);

// Decode a set of bboxes according to a set of prior bboxes.
    void DecodeBBoxes(const vector<NormalizedBBox>& prior_bboxes,
                      const vector<vector<float> >& prior_variances,
                      const CodeType code_type, const bool variance_encoded_in_target,
                      const bool clip_bbox, const vector<NormalizedBBox>& bboxes,
                      vector<NormalizedBBox>* decode_bboxes);

// Decode all bboxes in a batch.
    void DecodeBBoxesAll(const vector<LabelBBox>& all_loc_pred,
                         const vector<NormalizedBBox>& prior_bboxes,
                         const vector<vector<float> >& prior_variances,
                         const int num, const bool share_location,
                         const int num_loc_classes, const int background_label_id,
                         const CodeType code_type, const bool variance_encoded_in_target,
                         const bool clip, vector<LabelBBox>* all_decode_bboxes);

// Match prediction bboxes with ground truth bboxes.
    void MatchBBox(const vector<NormalizedBBox>& gt,
                   const vector<NormalizedBBox>& pred_bboxes, const int label,
                   const MatchType match_type, const float overlap_threshold,
                   const bool ignore_cross_boundary_bbox,
                   vector<int>* match_indices, vector<float>* match_overlaps);

// Find matches between prediction bboxes and ground truth bboxes.
//    all_loc_preds: stores the location prediction, where each item contains
//      location prediction for an image.
//    all_gt_bboxes: stores ground truth bboxes for the batch.
//    prior_bboxes: stores all the prior bboxes in the format of NormalizedBBox.
//    prior_variances: stores all the variances needed by prior bboxes.
//    multibox_loss_param: stores the parameters for MultiBoxLossLayer.
//    all_match_overlaps: stores jaccard overlaps between predictions and gt.
//    all_match_indices: stores mapping between predictions and ground truth.
    void FindMatches(const vector<LabelBBox>& all_loc_preds,
                     const map<int, vector<NormalizedBBox> >& all_gt_bboxes,
                     const vector<NormalizedBBox>& prior_bboxes,
                     const vector<vector<float> >& prior_variances,
                     const MultiBoxLossParameter& multibox_loss_param,
                     vector<map<int, vector<float> > >* all_match_overlaps,
    vector<map<int, vector<int> > >* all_match_indices);

// Count the number of matches from the match indices.
    int CountNumMatches(const vector<map<int, vector<int> > >& all_match_indices,
    const int num);

// Mine the hard examples from the batch.
//    conf_blob: stores the confidence prediction.
//    all_loc_preds: stores the location prediction, where each item contains
//      location prediction for an image.
//    all_gt_bboxes: stores ground truth bboxes for the batch.
//    prior_bboxes: stores all the prior bboxes in the format of NormalizedBBox.
//    prior_variances: stores all the variances needed by prior bboxes.
//    all_match_overlaps: stores jaccard overlap between predictions and gt.
//    multibox_loss_param: stores the parameters for MultiBoxLossLayer.
//    all_match_indices: stores mapping between predictions and ground truth.
//    all_loc_loss: stores the confidence loss per location for each image.
    template <typename Dtype>
    void MineHardExamples(const Blob<Dtype>& conf_blob,
                          const vector<LabelBBox>& all_loc_preds,
                          const map<int, vector<NormalizedBBox> >& all_gt_bboxes,
                          const vector<NormalizedBBox>& prior_bboxes,
                          const vector<vector<float> >& prior_variances,
                          const vector<map<int, vector<float> > >& all_match_overlaps,
    const MultiBoxLossParameter& multibox_loss_param,
    int* num_matches, int* num_negs,
            vector<map<int, vector<int> > >* all_match_indices,
    vector<vector<int> >* all_neg_indices);

// Retrieve bounding box ground truth from gt_data.
//    gt_data: 1 x 1 x num_gt x 7 blob.
//    num_gt: the number of ground truth.
//    background_label_id: the label for background class which is used to do
//      santity check so that no ground truth contains it.
//    all_gt_bboxes: stores ground truth for each image. Label of each bbox is
//      stored in NormalizedBBox.
    template <typename Dtype>
    void GetGroundTruth(const Dtype* gt_data, const int num_gt,
                        const int background_label_id, const bool use_difficult_gt,
                        map<int, vector<NormalizedBBox> >* all_gt_bboxes);
// Store ground truth bboxes of same label in a group.
    template <typename Dtype>
    void GetGroundTruth(const Dtype* gt_data, const int num_gt,
                        const int background_label_id, const bool use_difficult_gt,
                        map<int, LabelBBox>* all_gt_bboxes);

// Get location predictions from loc_data.
//    loc_data: num x num_preds_per_class * num_loc_classes * 4 blob.
//    num: the number of images.
//    num_preds_per_class: number of predictions per class.
//    num_loc_classes: number of location classes. It is 1 if share_location is
//      true; and is equal to number of classes needed to predict otherwise.
//    share_location: if true, all classes share the same location prediction.
//    loc_preds: stores the location prediction, where each item contains
//      location prediction for an image.
    template <typename Dtype>
    void GetLocPredictions(const Dtype* loc_data, const int num,
                           const int num_preds_per_class, const int num_loc_classes,
                           const bool share_location, vector<LabelBBox>* loc_preds);

// Encode the localization prediction and ground truth for each matched prior.
//    all_loc_preds: stores the location prediction, where each item contains
//      location prediction for an image.
//    all_gt_bboxes: stores ground truth bboxes for the batch.
//    all_match_indices: stores mapping between predictions and ground truth.
//    prior_bboxes: stores all the prior bboxes in the format of NormalizedBBox.
//    prior_variances: stores all the variances needed by prior bboxes.
//    multibox_loss_param: stores the parameters for MultiBoxLossLayer.
//    loc_pred_data: stores the location prediction results.
//    loc_gt_data: stores the encoded location ground truth.
    template <typename Dtype>
    void EncodeLocPrediction(const vector<LabelBBox>& all_loc_preds,
                             const map<int, vector<NormalizedBBox> >& all_gt_bboxes,
                             const vector<map<int, vector<int> > >& all_match_indices,
    const vector<NormalizedBBox>& prior_bboxes,
    const vector<vector<float> >& prior_variances,
    const MultiBoxLossParameter& multibox_loss_param,
            Dtype* loc_pred_data, Dtype* loc_gt_data);

// Compute the localization loss per matched prior.
//    loc_pred: stores the location prediction results.
//    loc_gt: stores the encoded location ground truth.
//    all_match_indices: stores mapping between predictions and ground truth.
//    num: number of images in the batch.
//    num_priors: total number of priors.
//    loc_loss_type: type of localization loss, Smooth_L1 or L2.
//    all_loc_loss: stores the localization loss for all priors in a batch.
    template <typename Dtype>
    void ComputeLocLoss(const Blob<Dtype>& loc_pred, const Blob<Dtype>& loc_gt,
                        const vector<map<int, vector<int> > >& all_match_indices,
    const int num, const int num_priors, const LocLossType loc_loss_type,
            vector<vector<float> >* all_loc_loss);

// Get confidence predictions from conf_data.
//    conf_data: num x num_preds_per_class * num_classes blob.
//    num: the number of images.
//    num_preds_per_class: number of predictions per class.
//    num_classes: number of classes.
//    conf_preds: stores the confidence prediction, where each item contains
//      confidence prediction for an image.
    template <typename Dtype>
    void GetConfidenceScores(const Dtype* conf_data, const int num,
                             const int num_preds_per_class, const int num_classes,
                             vector<map<int, vector<float> > >* conf_scores);

// Get confidence predictions from conf_data.
//    conf_data: num x num_preds_per_class * num_classes blob.
//    num: the number of images.
//    num_preds_per_class: number of predictions per class.
//    num_classes: number of classes.
//    class_major: if true, data layout is
//      num x num_classes x num_preds_per_class; otherwise, data layerout is
//      num x num_preds_per_class * num_classes.
//    conf_preds: stores the confidence prediction, where each item contains
//      confidence prediction for an image.
    template <typename Dtype>
    void GetConfidenceScores(const Dtype* conf_data, const int num,
                             const int num_preds_per_class, const int num_classes,
                             const bool class_major, vector<map<int, vector<float> > >* conf_scores);

// Compute the confidence loss for each prior from conf_data.
//    conf_data: num x num_preds_per_class * num_classes blob.
//    num: the number of images.
//    num_preds_per_class: number of predictions per class.
//    num_classes: number of classes.
//    background_label_id: it is used to skip selecting max scores from
//      background class.
//    loss_type: compute the confidence loss according to the loss type.
//    all_match_indices: stores mapping between predictions and ground truth.
//    all_gt_bboxes: stores ground truth bboxes from the batch.
//    all_conf_loss: stores the confidence loss per location for each image.
    template <typename Dtype>
    void ComputeConfLoss(const Dtype* conf_data, const int num,
                         const int num_preds_per_class, const int num_classes,
                         const int background_label_id, const ConfLossType loss_type,
                         const vector<map<int, vector<int> > >& all_match_indices,
    const map<int, vector<NormalizedBBox> >& all_gt_bboxes,
            vector<vector<float> >* all_conf_loss);

// Compute the negative confidence loss for each prior from conf_data.
//    conf_data: num x num_preds_per_class * num_classes blob.
//    num: the number of images.
//    num_preds_per_class: number of predictions per class.
//    num_classes: number of classes.
//    background_label_id: it is used to skip selecting max scores from
//      background class.
//    loss_type: compute the confidence loss according to the loss type.
//    all_conf_loss: stores the confidence loss per location for each image.
    template <typename Dtype>
    void ComputeConfLoss(const Dtype* conf_data, const int num,
                         const int num_preds_per_class, const int num_classes,
                         const int background_label_id, const ConfLossType loss_type,
                         vector<vector<float> >* all_conf_loss);

// Encode the confidence predictions and ground truth for each matched prior.
//    conf_data: num x num_priors * num_classes blob.
//    num: number of images.
//    num_priors: number of priors (predictions) per image.
//    multibox_loss_param: stores the parameters for MultiBoxLossLayer.
//    all_match_indices: stores mapping between predictions and ground truth.
//    all_neg_indices: stores the indices for negative samples.
//    all_gt_bboxes: stores ground truth bboxes for the batch.
//    conf_pred_data: stores the confidence prediction results.
//    conf_gt_data: stores the confidence ground truth.
    template <typename Dtype>
    void EncodeConfPrediction(const Dtype* conf_data, const int num,
                              const int num_priors, const MultiBoxLossParameter& multibox_loss_param,
                              const vector<map<int, vector<int> > >& all_match_indices,
    const vector<vector<int> >& all_neg_indices,
    const map<int, vector<NormalizedBBox> >& all_gt_bboxes,
            Dtype* conf_pred_data, Dtype* conf_gt_data);

// Get prior bounding boxes from prior_data.
//    prior_data: 1 x 2 x num_priors * 4 x 1 blob.
//    num_priors: number of priors.
//    prior_bboxes: stores all the prior bboxes in the format of NormalizedBBox.
//    prior_variances: stores all the variances needed by prior bboxes.
    template <typename Dtype>
    void GetPriorBBoxes(const Dtype* prior_data, const int num_priors,
                        vector<NormalizedBBox>* prior_bboxes,
                        vector<vector<float> >* prior_variances);

// Get detection results from det_data.
//    det_data: 1 x 1 x num_det x 7 blob.
//    num_det: the number of detections.
//    background_label_id: the label for background class which is used to do
//      santity check so that no detection contains it.
//    all_detections: stores detection results for each class from each image.
    template <typename Dtype>
    void GetDetectionResults(const Dtype* det_data, const int num_det,
                             const int background_label_id,
                             map<int, LabelBBox>* all_detections);

// Get top_k scores with corresponding indices.
//    scores: a set of scores.
//    indices: a set of corresponding indices.
//    top_k: if -1, keep all; otherwise, keep at most top_k.
//    score_index_vec: store the sorted (score, index) pair.
    void GetTopKScoreIndex(const vector<float>& scores, const vector<int>& indices,
                           const int top_k, vector<pair<float, int> >* score_index_vec);

// Get max scores with corresponding indices.
//    scores: a set of scores.
//    threshold: only consider scores higher than the threshold.
//    top_k: if -1, keep all; otherwise, keep at most top_k.
//    score_index_vec: store the sorted (score, index) pair.
    void GetMaxScoreIndex(const vector<float>& scores, const float threshold,
                          const int top_k, vector<pair<float, int> >* score_index_vec);

// Get max scores with corresponding indices.
//    scores: an array of scores.
//    num: number of total scores in the array.
//    threshold: only consider scores higher than the threshold.
//    top_k: if -1, keep all; otherwise, keep at most top_k.
//    score_index_vec: store the sorted (score, index) pair.
    template <typename Dtype>
    void GetMaxScoreIndex(const Dtype* scores, const int num, const float threshold,
                          const int top_k, vector<pair<Dtype, int> >* score_index_vec);

// Get max scores with corresponding indices.
//    scores: a set of scores.
//    threshold: only consider scores higher than the threshold.
//    top_k: if -1, keep all; otherwise, keep at most top_k.
//    score_index_vec: store the sorted (score, index) pair.
    void GetMaxScoreIndex(const vector<float>& scores, const float threshold,
                          const int top_k, vector<pair<float, int> >* score_index_vec);

// Do non maximum suppression given bboxes and scores.
//    bboxes: a set of bounding boxes.
//    scores: a set of corresponding confidences.
//    threshold: the threshold used in non maximum suppression.
//    top_k: if not -1, keep at most top_k picked indices.
//    reuse_overlaps: if true, use and update overlaps; otherwise, always
//      compute overlap.
//    overlaps: a temp place to optionally store the overlaps between pairs of
//      bboxes if reuse_overlaps is true.
//    indices: the kept indices of bboxes after nms.
    void ApplyNMS(const vector<NormalizedBBox>& bboxes, const vector<float>& scores,
                  const float threshold, const int top_k, const bool reuse_overlaps,
                  map<int, map<int, float> >* overlaps, vector<int>* indices);

    void ApplyNMS(const vector<NormalizedBBox>& bboxes, const vector<float>& scores,
                  const float threshold, const int top_k, vector<int>* indices);

    void ApplyNMS(const bool* overlapped, const int num, vector<int>* indices);

// Do non maximum suppression given bboxes and scores.
// Inspired by Piotr Dollar's NMS implementation in EdgeBox.
// https://goo.gl/jV3JYS
//    bboxes: a set of bounding boxes.
//    scores: a set of corresponding confidences.
//    score_threshold: a threshold used to filter detection results.
//    nms_threshold: a threshold used in non maximum suppression.
//    eta: adaptation rate for nms threshold (see Piotr's paper).
//    top_k: if not -1, keep at most top_k picked indices.
//    indices: the kept indices of bboxes after nms.
    void ApplyNMSFast(const vector<NormalizedBBox>& bboxes,
                      const vector<float>& scores, const float score_threshold,
                      const float nms_threshold, const float eta, const int top_k,
                      vector<int>* indices);

// Do non maximum suppression based on raw bboxes and scores data.
// Inspired by Piotr Dollar's NMS implementation in EdgeBox.
// https://goo.gl/jV3JYS
//    bboxes: an array of bounding boxes.
//    scores: an array of corresponding confidences.
//    num: number of total boxes/confidences in the array.
//    score_threshold: a threshold used to filter detection results.
//    nms_threshold: a threshold used in non maximum suppression.
//    eta: adaptation rate for nms threshold (see Piotr's paper).
//    top_k: if not -1, keep at most top_k picked indices.
//    indices: the kept indices of bboxes after nms.
    template <typename Dtype>
    void ApplyNMSFast(const Dtype* bboxes, const Dtype* scores, const int num,
                      const float score_threshold, const float nms_threshold,
                      const float eta, const int top_k, vector<int>* indices);

// Compute cumsum of a set of pairs.
    void CumSum(const vector<pair<float, int> >& pairs, vector<int>* cumsum);

// Compute average precision given true positive and false positive vectors.
//    tp: contains pairs of scores and true positive.
//    num_pos: number of positives.
//    fp: contains pairs of scores and false positive.
//    ap_version: different ways of computing Average Precision.
//      Check https://sanchom.wordpress.com/tag/average-precision/ for details.
//      11point: the 11-point interpolated average precision. Used in VOC2007.
//      MaxIntegral: maximally interpolated AP. Used in VOC2012/ILSVRC.
//      Integral: the natural integral of the precision-recall curve.
//    prec: stores the computed precisions.
//    rec: stores the computed recalls.
//    ap: the computed Average Precision.
    void ComputeAP(const vector<pair<float, int> >& tp, const int num_pos,
                   const vector<pair<float, int> >& fp, const string ap_version,
                   vector<float>* prec, vector<float>* rec, float* ap);

#ifdef USE_OPENCV
    vector<cv::Scalar> GetColors(const int n);

template <typename Dtype>
void VisualizeBBox(const vector<cv::Mat>& images, const Blob<Dtype>* detections,
                   const float threshold, const vector<cv::Scalar>& colors,
                   const map<int, string>& label_to_display_name,
                   const string& save_file);
#endif  // USE_OPENCV

}  // namespace caffe

}   // namespace ts

#endif  // CAFFE_UTIL_BBOX_UTIL_H_